#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright 2013, Stephen Finucane

# Author: Stephen Finucane <stephenfinucane@hotmail.com>

""" Sample application demonstrating use of pyblehci to write/read from a serial device """

import sys
import collections
import serial
import time
import struct
import threading

from pyblehci import BLEBuilder
from pyblehci import BLEParser

class ResultRecv(threading.Thread):
	
	def __init__(self, callback=None):		
		super(ResultRecv, self).__init__()
		self._callback = None
		self._thread_continue = False
		self._stop = threading.Event()
		
		if callback:
			self._callback = callback
			self._thread_continue = True
			self.start()
	
	def run(self):
		while True:
			self._callback(self.name)


def pretty(hex_string, seperator=None):
	# >>> pretty("\x01\x02\x03\xff")
	#       '01 02 03 FF'
	if seperator: 
		sep = seperator 
	else: sep = ' '
	hex_string = hex_string.encode('hex')
	a = 0
	out = ''
	for i in range(len(hex_string)):
		if a == 2:
			out = out + sep
			a = 0
		out = out + hex_string[i].capitalize()
		a = a + 1
	return out

def print_orderedDict(dictionary):
	result = ""
	for idx, key in enumerate(dictionary.keys()):
		if dictionary[key]:
			#convert e.g. "data_len" -> "Data Len"
			title = ' '.join(key.split("_")).title()
			if isinstance(dictionary[key], list):
				for idx2, item in enumerate(dictionary[key]):
					result += "{0} ({1})\n".format(title, idx2)
					result += print_orderedDict(dictionary[key][idx2])
			elif isinstance(dictionary[key], type(collections.OrderedDict())):
				result += '{0}\n{1}'.format(title, print_orderedDict(dictionary[key]))
			else:
				result += "{0:15}\t: {1}\n\t\t  ({2})\n".format(title, pretty(dictionary[key][0], ':'), dictionary[key][1])
		else:
			result += "{0:15}\t: None".format(key)
	return result

def print_output((packet, dictionary)):
	result = print_orderedDict(dictionary)
	result += 'Dump:\n{0}\n'.format(pretty(packet))
	return result
		
def analyse_packet((packet, dictionary)):	
	global print_packet
	global packet_list
	
	#print("EVENT: Response received from the device")	
	packet = packet.encode("hex")
	if packet[6:10] == "0d06" and packet[12:14] == "04":
		addr1, addr2, addr3, addr4, addr5, addr6 = struct.unpack('2s2s2s2s2s2s',packet[16:28])
		address = addr1.upper()+":"+addr2.upper()+":"+addr3.upper()+":"+addr4.upper()+":"+addr5.upper()+":"+addr6.upper()
		print address
	elif packet[6:10] == "1b05":
		"""
		Type: 0x04 (Event)
		EventCode: 0xFF (HCI_LE_ExtEvent)
		Data Length: 0x0A bytes(s)
		Event: 0x051B (ATT_HandleValueNotification)
		Status: 0x00 (Success)
		ConnHandle: 0x0000
		EventLen: 0x04
		AttrHandle: 0x003A
		Value: 4A 04
		Dump(Rx):
		04 FF 0A 1B 05 00 00 00 04 3A 00 4A 04
		"""
		conn_handle = packet[12:16]
		value = packet[22:len(packet)]
		#print "connect_handle: " + conn_handle
		#print "value: " + value + "\n"
		packet_list.append([dic[conn_handle], value])
		#for item in packet_list:
			#print item
		#print ""	
		
	elif print_packet == 1:
		packet = packet.decode("hex")
		print(print_output((packet, dictionary)))
		
def connect_device(inaddr):
	
	global ble_builder
	global device_list
	
	addr = inaddr.replace(':', "")
	#device_list[device_list(list)-1].append(addr)
	#device_list.sort()
	addr = addr.decode("hex")
	ble_builder.send("fe09", peer_addr=addr)

def find_result(name):
	global packet_list
	i = 0

	for item in packet_list:
		if name in item:
			#print item[1]
			print name, packet_list.pop(i)
			break
		i += 1
	
	
	
def Recv_Command():
	global print_packet
	
	while(1):
		indata = raw_input("Input Command:\n").split(',')
		
		if indata[0] == "c":
			connect_device(indata[1])
		elif indata[0] == "printpacket":
			if indata[1] == "ON":
				print_packet = 1
			elif indata[1] == "OFF":
				print_packet = 0
		else:
			print("No such command")
		
def communicate(code):
	#initialise objects

	global serial_port	
	global ble_builder 	
	global ble_parser
	global print_packet
	
	#initialise the device
	print("COMMAND: Initialising device")
	ble_builder.send("fe00")
	#get an operating parameter value
	print("COMMAND: Getting operating parameter value")
	ble_builder.send("fe31", param_id="\x15")
	#start a device discovery scan
	print("COMMAND: Starting device scan")
	ble_builder.send("fe04", mode="\x03")
	#sleep main thread for 15 seconds - allow results of device scan to return
	time.sleep(5)
	#cancel scan
	print("COMMAND: Canceling device scan")
	ble_builder.send("fe05")
		
	Recv_Command()
	
	#ble_builder.send("fe09", peer_addr=ADDR)
	#connect a device
	#print("COMMAND: Connect device")
	#ble_builder.send("fe09", peer_addr="\xFF\xFF\xFF\xFF\xFF\x77")
	#time.sleep(5)
	#ble_builder.send("fd8a", handle="\x25\x00")
	#time.sleep(5)
	#ble_builder.send("fd92", handle="\x25\x00", value="\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
	#time.sleep(1)
	#ble_builder.send("fd8a", handle="\x25\x00")
	
	#initialise the device
	#print("COMMAND: Initialising device")
	#print(print_output(ble_builder.send("fe00")))
	#get an operating parameter value
	#print("COMMAND: Getting operating parameter value")
	#print(print_output(ble_builder.send("fe31", param_id="\x15")))
	#start a device discovery scan
	#print("COMMAND: Starting device scan")
	#print(print_output(ble_builder.send("fe04", mode="\x03")))
	#sleep main thread for 15 seconds - allow results of device scan to return
	#time.sleep(5)
	#cancel scan
	#print("COMMAND: Canceling device scan")
	#print(print_output(ble_builder.send("fe05")))
	#connect a device
	#print("COMMAND: Connect device")
	#print(print_output(ble_builder.send("fe09", peer_addr="\xFF\xFF\xFF\xFF\xFF\x77")))
	#time.sleep(5)
	#print(print_output(ble_builder.send("fd8a", handle="\x25\x00")))
	#time.sleep(5)
	#print(print_output(ble_builder.send("fd92", handle="\x25\x00", value="\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")))
	#time.sleep(1)
	#print(print_output(ble_builder.send("fd8a", handle="\x25\x00")))
	#close device
	#ble_parser.stop()

if __name__ == "__main__":
	
	global serial_port	
	global ble_builder 	
	global ble_parser
	global packet_list
	global recv1
	
	packet_list = []
	dic = {'0001': 'Thread-1', '0000': 'Thread-2'}
	serial_port = serial.Serial(port='COM4', baudrate=57600)
	ble_builder = BLEBuilder(serial_port)
	ble_parser = BLEParser(serial_port, callback=analyse_packet)
	print_packet = 0
	recv1 = ResultRecv(callback = find_result)
	
	code = "00aaffaaffaa"
	communicate(code)
	
	
	
	